package com.jacklei.ch07;
/*
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢？

 

示例 1：

输入：n = 2
输出：2
解释：有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2：

输入：n = 3
输出：3
解释：有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
 

提示：

1 <= n <= 45

来源：力扣（LeetCode）
链接：https://leetcode.cn/problems/climbing-stairs
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。*/
public class ClimbingStairs {
    public static void main(String[] args) {
        ClimbingStairs c = new ClimbingStairs();
        for (int i = 1; i < 100; i++){
        System.out.print("n:\t"+i +"\t=>"+ c.climbStairs1(i));
        System.out.println("\tn:\t"+i +"\t=>"+ c.climbStairs2(i));
        }
    }
//    public int climbStairs2(int n) {
//        int[][] q = {{1, 1}, {1, 0}};
//        int[][] res = pow(q, n);
//        return res[0][0];
//    }
//
//    public int[][] pow(int[][] a, int n) {
//        int[][] ret = {{1, 0}, {0, 1}};
//        while (n > 0) {
//            if ((n & 1) == 1) {
//                ret = multiply(ret, a);
//            }
//            n >>= 1;
//            a = multiply(a, a);
//        }
//        return ret;
//    }
//
//    public int[][] multiply(int[][] a, int[][] b) {
//        int[][] c = new int[2][2];
//        for (int i = 0; i < 2; i++) {
//            for (int j = 0; j < 2; j++) {
//                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
//            }
//        }
//        return c;
//    }

    public int climbStairs2(int n){
        //if(n < 3) return n;
        int [][] q = {{1,1},{1,0}};
        int[][] res = pow(q,n);
        return res[0][0];
    }

    private int[][] pow(int[][] a, int n) {
        int[][] ret = {{1,0},{0,1}};
        while (n > 0){
            if((n & 1)==1){
                ret = multiply(ret,a);
            }
            n >>= 1;
            a = multiply(a,a);
        }
        return ret;
    }

    private int[][] multiply(int[][] a, int[][] b) {
        int[][] c = new int[2][2];
        for (int i = 0; i < 2; i++){
            for (int j = 0; j < 2; j++){
                c[i][j] = a[i][0]*b[0][j] + a[i][1]* b[1][j];
            }
        }
        return c;
    }

    public int climbStairs1(int n){
        if(n <= 3) return n;
        int f = 2;
        int s = 3;
        int cur = 0;
        for (int i = 4; i < n+1; i++){
            cur = f+s;
            f = s ;
            s = cur;
        }
       return cur;
    }

    public int climbStairs(int n) {
        if (n < 0) return 0;
        if (n == 0) return 1;
        return climbStairs(n-1) +climbStairs(n-2);
    }
}
